<?php

	// When we have this active, Facebook realtime updates are NOT working!
	$allowed = array(
		'77.248.91.44',
		'88.159.7.151',
		'212.178.116.242',
		'62.194.132.67',
		'77.248.227.223',
		'77.161.138.169',
		'80.101.164.93',
		'193.190.58.254'
	);
	
	if(!in_array($_SERVER['REMOTE_ADDR'], $allowed)){
		exit;
	}

	// The precision is the point where PHP will convert an int to float, 
	// we don't want want this too soon else PHP will fuck up the high userid's
	// that we get from the Facebook api.
	ini_set('precision', 20);
	
    error_reporting(E_ALL);
	ini_set('display_errors', true);
	
    define('ROOT_PATH', realpath(dirname(__FILE__)) . '/');
    define('APP_PATH', ROOT_PATH . 'hikle/');
    define('FW_PATH', ROOT_PATH . 'framework/');
    define('URL', 'http://hikle.nl/');
    define('DEFAULT_LANGUAGE', 'nl');
    define('SESSION_DURATION', 15);
    define('SESSION_LANGUAGE_PREFIX_KEY_NAME', 'language_prefix');
    
    include(FW_PATH . 'functions.php');
    
    // Disable internet explorer 6.
	if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 6.0')){
		displayView('errors/upgrade_browser');
		exit;
	}
	
	// Autoload models.
	function __autoload($className) {
		if(file_exists(APP_PATH . 'models/' . strtolower($className) . '.php')){
			include(APP_PATH . 'models/' . strtolower($className) . '.php');
		} else if(file_exists(APP_PATH . 'classes/' . strtolower($className) . '.php')){
			include(APP_PATH . 'classes/' . strtolower($className) . '.php');
		}
	}
    
    $app = Application::getInstance();
    $app->run(array(
    	'databaseConnections' => array(
    		'default' => array(
    			'host' => 'localhost',
    			'port' => 3306,
    			'name' => 'vemicom_hikle',
    			'username' => 'vemicom_hikle',
    			'password' => '9060SXRX331'
    		)
    	)
    ));
	
	// Lets make sure the cookie is available on the whole domain.
    $currentCookieParameters = session_get_cookie_params();

	session_set_cookie_params( 
	    $currentCookieParameters["lifetime"], 
	    $currentCookieParameters["path"], 
	    '.hikle.nl', 
	    $currentCookieParameters["secure"], 
	    $currentCookieParameters["httponly"] 
	); 
    
	/**
	 * Our main class that will handle our whole application.
	 */
	class Application{
		
		/**
		 *
		 * @var object static singleton.
		 */
		private static $instance;
		
		/**
		 *
		 * @var array configuration.
		 */
		private $config;
		
		/**
		 *
		 * @var string name of the controllers.
		 */
		private $controller;
		
		/**
		 *
		 * @var string the name of the action.
		 */
		private $action;
		
		/**
		 *
		 * @var array parameters (/users/1 <- 1 = parameters etc.)
		 */
		private $parameters;
		
		/**
		 *
		 * @var string of the controller file.
		 */
        private $controllerFile;
		
		/**
		 *
		 * @var class instance of the controller.
		 */
		private $controllerObject;
		
		/**
		 *
		 * @var array with objects, (database connections).
		 */
		private $databaseConnections;
        
		/**
		 * Singleton.
		 * @return object instance.
		 */
		public static function &getInstance(){
			if(!isset(self::$instance)){
				self::$instance = new Application();
			}
			
			return self::$instance;
		}
		
		/**
		 *
		 * @param string $name database name
		 * @return object
		 */
		public function &database($name){
			if(!isset($this->databaseConnections[$name])){
				$settings =& $this->config['databaseConnections'][$name];
				$this->databaseConnections[$name] = new Mysql_Database(
					$settings['host'], 
					$settings['port'], 
					$settings['name'],
					$settings['username'], 
					$settings['password']
				);
			}
			
			return $this->databaseConnections[$name];
		}
        
		/**
		 *
		 * @param array $config
		 */
		public function run($config){
			$this->config =& $config;
			$session = new Session_Handler($this->database('default'));
			
			if(!isset($_SESSION[SESSION_LANGUAGE_PREFIX_KEY_NAME])){
				$_SESSION[SESSION_LANGUAGE_PREFIX_KEY_NAME] = DEFAULT_LANGUAGE;
			}
			
			$this->controller = 'index';
			$this->action = '_index';
			$this->parameters = array();
			
			if(isset($_SERVER['PATH_INFO'])){
				$explode = explode('/', $_SERVER['PATH_INFO']);
				
				if(empty($explode[0])){
					array_shift($explode);
				}
				
				if(!empty($explode[0])){					
					$this->controller = $explode[0];
					array_shift($explode);
					
					if(!empty($explode[0])){
						$this->action = $explode[0];
						array_shift($explode);
						$this->parameters = $explode;
					}
				}
			}
			
			$this->controllerFile = APP_PATH . 'controllers/' . $this->controller . '.php';
			
			if(file_exists($this->controllerFile)){
				include($this->controllerFile);
				$controllerClass = $this->controller;
				$this->controllerObject = new $controllerClass;
			} else {
				$this->throwError('page_not_found');
			}
			
			$this->controllerObject->app =& $this;
			
			// Facebook communicator, used on everypage, put it in the memory.
			data('fb', new Facebook_Communicator());
			
			if(method_exists($this->controllerObject, 'load')){
				call_user_func(array($this->controllerObject, 'load'));
			}
			
			if(method_exists($this->controllerObject, $this->action)){
				if(count($this->parameters) > 0){
					call_user_func_array(array($this->controllerObject, $this->action), $this->parameters);
				} else {
					call_user_func(array($this->controllerObject, $this->action));
				}
			} else {
				$this->throwError('page_not_found');
			}
		}
		
		/**
		 *
		 * @param string $name name of the error thrown.
		 */
		public function throwError($name){
			displayView('errors/' . $name);
			exit;
		}
	}

	/**
	 * PDO mysql database class, just to speed default queries up a little.
	 */
	class Mysql_Database extends Pdo{
		
		/**
		 *
		 * @param string $host
		 * @param string $port
		 * @param string $name
		 * @param string $username
		 * @param string $password
		 */
		public function __construct($host, $port, $name, $username, $password){
			parent::__construct('mysql:host=' . $host . ';port=' . $port . ';dbname=' . $name . ';charset=UTF-8', $username, $password);
			
			// Very important! Else we get werid characters and bullshit.
			$this->exec('SET NAMES utf8');
		}
		
		/**
		 *
		 * @param string $query
		 * @param array $parameters
		 * @return array query, parameters, success, lastInsertId, rowCount, result.
		 */
		public function query($query, $parameters = null){
			$stmt = $this->prepare($query);
			$stmt->setFetchMode(PDO::FETCH_ASSOC);
			$returnArray = null;
			$returnArray['query'] =& $query;
			$returnArray['parameters'] =& $parameters;
			
			if($parameters !== null){
				$returnArray['success'] = $stmt->execute($parameters);
			} else {
				$returnArray['success'] = $stmt->execute();
			}
			
			$error =& $stmt->errorInfo();
			
			if($error[0] !== '00000'){
				dump($returnArray);
				dump($error[2]);
				exit;
			}
			
			$returnArray['lastInsertId'] = $this->lastInsertId();
			$returnArray['rowCount'] = $stmt->rowCount();
			$returnArray['result'] = $stmt->fetchAll();
			
			return $returnArray;
		}
	}
	
	/**
	 * Database sessions.
	 */
	class Session_Handler{
		
		/**
		 *
		 * @var object database handler.
		 */
		private $db;
		
		/**
		 *
		 * @param object $db
		 */
		public function __construct($db){
			$this->db = $db;
            
			session_set_save_handler(
				array($this, 'open'),
				array($this, 'close'),
				array($this, 'read'),
				array($this, 'write'),
				array($this, 'destroy'),
				array($this, 'gc')				
			);
			
			register_shutdown_function('session_write_close');
			session_start();
		}
		
		/**
		 *
		 * @return true
		 */
		public function open(){
			return true;
		}
		
		/**
		 *
		 * @return true
		 */
		public function close(){
			return true;
		}
		
		/**
		 *
		 * @param string $id
		 * @return mixed returns the data from the database if exists.
		 */
		public function read($id){
			$stmt = $this->db->query('SELECT `data` FROM `sessions` WHERE `id` = ?', array($id));
			
			if($stmt['rowCount'] > 0){
				return $stmt['result'][0]['data'];
			}
			
			return null;
		}
		
		/**
		 *
		 * @param string $id
		 * @param array $data
		 * @return bool
		 */
		public function write($id, $data){
			$stmt = $this->db->query('REPLACE INTO `sessions` VALUES (?, ?, NOW())', array($id, $data));
			return $stmt['success'];
		}
		
		/**
		 *
		 * @param string $id
		 * @return bool
		 */
		public function destroy($id){
			$stmt = $this->db->query('DELETE FROM `sessions` WHERE `id` = ?', array($id));
			return $stmt['success'];
		}
		
		/**
		 *
		 * @param string $max
		 * @return bool
		 */
		public function gc($max){
			$stmt = $this->db->query('DELETE FROM `sessions` WHERE `lastUpdated` < DATE_SUB(NOW(), INTERVAL ' . SESSION_DURATION . ' MINUTE)');
			return $stmt['success'];
		}
	}
    
// File end.